#To-do list:
#Overwriting and deleting old page values
#More editable parameters ie site title
#jQuery admin interface
#Blog module
#Allow webapp code to be inserted through admin interface
#Create SEO module
#Memcaching
#Templates-in progress
#Greater menu control (order 0 means no item?)
#Suckerfish dropdowns
#Image support via media blob upload
#Better authentication support

#Imports:
import os
import logging
import wsgiref.handlers
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp import util
from google.appengine.ext import db
from google.appengine.api import users
from util.sessions import Session
import hashlib

#Functions:
#Content() adds text to the page.
def Content(pages, path):
    content=""
    match = False
    for page in pages:
        if page.Title.lower() == path:
            content += str(page.Content)
            match = True
            break    
    if match == False:
        content = "Sorry, but this page does not exist"
    return content

def doRender(handler, tname = 'index.htm', values = { }):
  temp = os.path.join(
      os.path.dirname(__file__),
      'templates/' + tname)
  if not os.path.isfile(temp):
    return False
  # Check to see if we are supposed to be rendering 
  # A non-html file
  binary = False
  if temp.endswith(".jpg") or temp.endswith(".jpeg"):
      handler.response.headers['Content-Type'] = 'image/jpeg'
      binary = True
  elif temp.endswith(".png"):
      handler.response.headers['Content-Type'] = 'image/png'
      binary = True
  if binary:
      outstr = open(temp, "rb").read()
      handler.response.out.write(outstr)
      return True
  
  # Make a copy of the dictionary and add the path and session
  newval = dict(values)
  newval['path'] = handler.request.path
  handler.session = Session()
  if 'username' in handler.session:
     newval['username'] = handler.session['username']

  outstr = template.render(temp, newval)
  handler.response.out.write(outstr)
  return True

#Data Models:

#The Page() model sets the properties for title, content, and menu order.
#Needs more properties
class Page(db.Model):
    Title = db.StringProperty()
    Content = db.TextProperty()
    Order = db.IntegerProperty()

#A model for a User
class User(db.Model):
    acct = db.StringProperty()
    pw = db.StringProperty()
    name = db.StringProperty()
    role = db.StringProperty()
    admin = db.BooleanProperty()

# A Model for Access
class Access(db.Model):
  account = db.StringProperty()
  path = db.StringProperty()
  when = db.DateTimeProperty(auto_now=True)
  
# A Model for a ChatMessage
class ChatMessage(db.Model):
  user = db.ReferenceProperty()
  text = db.StringProperty()
  created = db.DateTimeProperty(auto_now=True)

#Handlers: 

#Main() handles all requests for regular content based on the path.
#The home redirect is set here.  This should be replaced by a dynamic home page.
class Main(webapp.RequestHandler):
    def get(self):
        self.response.headers['Content-Type'] = 'text/html'
        #get the url and split on / into a list called path
        path = self.request.path.split('/')
        #get just the path
        pathstr = self.request.path+".htm"
        #get all Page() objects from the datastore
        pages = db.Query(Page)
        #the current home page. add field to AdminForm() and make this a datastore call
        HomeRedirect='/about'
        
        self.session = Session()
        
        if 'username' in self.session:
            username = self.session['username']
        else:
            username = ""
        
        if 'userrole' in self.session:
            role = self.session['userrole']
        
        else:
            role = 'anonymous'
        
        
        if path==['', '']:
            self.redirect(HomeRedirect)
        
        #all non-admin pages
        else:
            content = Content(pages,path[-1])
            doRender(self, 'index.htm', {'pages':pages,'url':path[-1],'content':content,'username':username})

#Consolidate admin interface through jQuery(AJAX)            
class AdminHandler(webapp.RequestHandler):

    def get(self):
        self.response.headers['Content-Type'] = 'text/html'
        #get the url and split on / into a list called path
        path = self.request.path.split('/')
        #get all Page() objects from the datastore
        pages = db.Query(Page)
                
        self.session = Session()
        
        if 'username' in self.session:
            username = self.session['username']
        else:
            username = ""
        
        if 'userrole' in self.session:
            role = self.session['userrole']
        else:
            role = 'anonymous'
            
        if 'admin' in self.session:
            admin = self.session['admin']
        else:
            admin = False
        
        #the admin page
        if admin==True or role=='superuser':
            greeting = "Welcome %s" % username
            authenticated = True
            title=""
            text=""
            order=""
            newaccess = Access(account=username, path=self.request.path);
            newaccess.put();
            if path[-2]=='admin':
                mypage=db.GqlQuery("SELECT * FROM Page WHERE Title='%s' LIMIT 1" % (str(path[-1])))
                for i in mypage:
                    title+=str(i.Title)
                    text+=str(i.Content)
                    order+=str(i.Order)
            doRender(self, 'admin.htm', {'pages':pages,'greeting':greeting,'title':title,'text':text,'order':order,'authenticated':authenticated})
        
        else:
            doRender(self, 'noauth.htm', {'pages':pages})
            
    def post(self):
        self.response.headers['Content-Type'] = 'text/html'
        #puts a new page in the datastore or updates existing page
        pagetitle=self.request.get('title')
        try:
            thispage=db.GqlQuery("SELECT * FROM Page WHERE Title='%s' LIMIT 1" % (str(pagetitle)))[0]
            thispage.Title = self.request.get('title')
            thispage.Content = self.request.get('content')
            thispage.Order = int(self.request.get('order'))
            thispage.put()
        except:
            page = Page()
            page.Title = self.request.get('title')
            page.Content = self.request.get('content')
            page.Order = int(self.request.get('order'))
            page.put()
                   
        self.redirect('/admin')
            
class LoginHandler(webapp.RequestHandler):

    def get(self):
        pages = db.Query(Page)
        doRender(self, 'loginscreen.htm',{'pages':pages})
        
    def post(self):
        pages=db.GqlQuery("SELECT * FROM Page ORDER BY Order ASC")
        self.session = Session()
        acct = self.request.get('account')
        pw = hashlib.sha1(self.request.get('password')).hexdigest()
        logging.info('Checking account='+acct+' pw='+pw)

        self.session.delete_item('username')
        self.session.delete_item('userkey')
    
        if pw == '' or acct == '':
            doRender(self,'loginscreen.htm',{'error' : 'Please specify Account and Password','pages':pages} )
            return
    
        que = db.Query(User)
        que = que.filter('acct =',acct)
        que = que.filter('pw = ',pw)

        results = que.fetch(limit=1)

        if len(results) > 0 :
            user = results[0]
            self.session['userkey'] = user.key()
            self.session['username'] = acct
            self.session['userrole'] = user.role
            self.session['admin'] = user.admin
            content = Content(pages,'about')
            doRender(self,'index.htm',{'pages':pages,'content':content,'url':'about'})
    
        else:
            doRender(self,'loginscreen.htm', {'error' : 'Incorrect password','pages':pages} )

class ApplyHandler(webapp.RequestHandler):

  def get(self):
    doRender(self, 'applyscreen.htm')

  def post(self):
    self.session = Session()
    name = self.request.get('name')
    acct = self.request.get('account')
    pw = hashlib.sha1(self.request.get('password')).hexdigest()
    role = 'user'
    admin = False
    logging.info('Adding account='+acct)
    pages=db.GqlQuery("SELECT * FROM Page ORDER BY Order ASC")

    if pw == '' or acct == '' or name == '':
        doRender(self,'applyscreen.htm',{'error' : 'Please fill in all fields'} )
        return

    # Check if the user already exists
    que = db.Query(User).filter('acct =',acct)
    results = que.fetch(limit=1)

    if len(results) > 0 :
        doRender(self,'applyscreen.htm',{'error' : 'Account Already Exists'} )
        return
        
    #Create the User object and log the user in
    newuser = User(acct=acct, pw=pw, name=name, role=role, admin=admin)
    pkey = newuser.put()
    self.session['username'] = acct
    self.session['userkey'] = pkey
    self.session['userrole'] = role
    self.session['admin'] = admin
    content = Content(pages,'about')
    doRender(self,'index.htm',{'pages':pages,'content':content,'url':'about'})


class MembersHandler(webapp.RequestHandler):

  def get(self):
    self.session = Session()
    username = self.session.get('username', None)
    if username == None:
        doRender(self,'noauth.htm')
        return
            
    newaccess = Access(account=username, path=self.request.path);
    newaccess.put();
    
    que = db.Query(User)
    user_list = que.fetch(limit=100)
    doRender(
        self, 
        '/private/memberscreen.htm', 
        {'user_list': user_list})

class LogoutHandler(webapp.RequestHandler):

  def get(self):
    pages=db.GqlQuery("SELECT * FROM Page ORDER BY Order ASC")
    content = Content(pages,'about')
    self.session = Session()
    self.session.delete_item('username')
    self.session.delete_item('userkey')
    self.session.delete_item('userrole')
    self.session.delete_item('admin')
    doRender(self, 'index.htm',{'pages':pages,'content':content,'url':'about'})

class ChatHandler(webapp.RequestHandler):

  def get(self):
    doRender(self,'chatscreen.htm')

  def post(self):
    self.session = Session()
    if not 'userkey' in self.session:
      doRender(
          self,
          'chatscreen.htm',
          {'error' : 'Must be logged in'} )
      return

    msg = self.request.get('message')
    if msg == '':
      doRender(
          self,
          'chatscreen.htm',
          {'error' : 'Blank message ignored'} )
      return

    newchat = ChatMessage(user = self.session['userkey'], text=msg)
    newchat.put();
    doRender(self,'chatscreen.htm')

class MessagesHandler(webapp.RequestHandler):

  def get(self):
    que = db.Query(ChatMessage).order('-created');
    chat_list = que.fetch(limit=10)
    doRender(self, 'messagelist.htm', {'chat_list': chat_list})

#Run App
def main():
    application = webapp.WSGIApplication([
        ('/login', LoginHandler),
        ('/apply', ApplyHandler),
        ('/logout', LogoutHandler),
        ('/chat', ChatHandler),
        ('/messages', MessagesHandler),
        ('/admin', AdminHandler),
        ('/admin/.*', AdminHandler),
        ('/.*',Main)],
        debug=True)
    util.run_wsgi_app(application)


if __name__ == '__main__':
    main()
